using System;
using AntEater.ComponentModel;
using AntEater.ComponentModel.BuildElements;
using System.Windows.Forms;
using AntEater.Runtime.Services.Building;
using System.IO;

namespace AntEater.Runtime.UI
{
    /// <summary>
    /// Presenter for the Target Execution View.
    /// </summary>
    public class TargetExecutionPresenter : PresenterBase, ITargetExecutionPresenter
    {
        /// <summary>
        /// Occurs if the selection of the Target Execution view changed.
        /// </summary>
        public event EventHandler<EventArgs> SelectionChanged;

        /// <summary>
        /// Occurs when a file shoud be opened in a specific view.
        /// </summary>
        public event EventHandler<BuildFileViewEventArgs> OpenFile;

        /// <summary>
        /// Initializes a new instance of the <see cref="TargetExecutionPresenter"/> class.
        /// </summary>
        public TargetExecutionPresenter()
            : base(new TargetExecutionView()) {
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        /// <param name="context">The context.</param>
        public override void Initialize(PresenterContext context) {

            // Initialize Presenter
            base.Initialize(context);
            this._options = context.Runtime.Options;
            this._options.Changed += new EventHandler<EventArgs>(this.OptionsChanged);

            this._project = context.Runtime.Solution.Project;

            // Initialize View
            this.View.SelectionChanged += new EventHandler<EventArgs>(this.OnSelectionChanged);
            this.View.ExecuteBuildFile += new EventHandler<EventArgs>(this.ViewExecuteBuildFile);
            this.View.AddBuildFile += new EventHandler<EventArgs>(this.ViewAddBuildFile);
            this.View.RemoveBuildFile += new EventHandler<EventArgs>(this.ViewRemoveBuildFile);
            this.View.EditExternalBuildProperties += new EventHandler<EventArgs>(this.ViewEditExternalBuildProperties);
            this.View.Refreshing += new EventHandler<EventArgs>(this.ViewRefreshing);
            this.View.OpenFile += new EventHandler<BuildFileViewEventArgs>(this.OnOpenFile);

            this.View.Project = this.Project;
            this.View.Options = this.Options;
            this.View.Refresh();
        }

        /// <summary>
        /// Gets the view.
        /// </summary>
        /// <value>The view.</value>
        public new TargetExecutionView View {
            get { return (TargetExecutionView)base.View; }
            protected set { base.View = value; }
        }

        private Options _options;

        /// <summary>
        /// Gets or sets the options.
        /// </summary>
        /// <value>The options.</value>
        public Options Options {
            get { return _options; }
        }


        private Project _project;

        /// <summary>
        /// Gets the project.
        /// </summary>
        /// <value>The project.</value>
        public Project Project {
            get { return _project; }
        }

        /// <summary>
        /// Gets the selected build file.
        /// </summary>
        /// <value>The selected build file.</value>
        public BuildFile SelectedBuildFile {
            get { return this.View.SelectedBuildFile; }
        }

        /// <summary>
        /// Gets the selected target.
        /// </summary>
        /// <value>The selected target.</value>
        public TargetBuildElement SelectedTarget {
            get { return this.View.SelectedTarget; }
        }

        /// <summary>
        /// Executes the build file.
        /// </summary>
        public void ExecuteBuildFile() {
            
            BuildFile buildFile = this.SelectedBuildFile;
            if (buildFile != null) {

                // Get the selected Target
                string[] target = new string[] {};
                if (this.SelectedTarget != null) {
                    target = new string[] { this.SelectedTarget.Name };
                }

                // Get building service
                IBuildingService buildingService = this.Context.Runtime.RuntimeServices.GetService(typeof(IBuildingService)) as IBuildingService;
                if (buildingService != null) {

                    // Add external properties to the building service
                    buildingService.ExternalBuildProperties.AddRange(_options.ExternalBuildProperties);
                    buildingService.ExternalBuildProperties.AddRange(_project.ExternalBuildProperties);
                    buildingService.ExternalBuildProperties.AddRange(buildFile.ExternalBuildProperties);

                    bool result = false;

                    // Build the build file
                    using (Stream stream = File.Open(buildFile.BuildFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
                        result = buildingService.Build(stream, buildFile.BuildFilePath, target);
                    }

                    if (result == true) {
                        this.View.State = TargetExecutionState.Succeeded;
                    } else {
                        this.View.State = TargetExecutionState.Failed;
                    }
                }
            }
        }

        /// <summary>
        /// Adds the build file.
        /// </summary>
        public void AddBuildFile() {

            // Show build file selector
            using (BuildFileSelectorView selector = new BuildFileSelectorView()) {
                selector.Solution = this.Context.Runtime.Solution;

                // Add choosen build file to the project
                if (selector.ShowDialog() == DialogResult.OK) {
                    if (this.Project.BuildFiles.Contains(selector.SelectedBuildFile) == false) {
                        this.Project.BuildFiles.Add(selector.SelectedBuildFile);
                    }
                }
            }
        }

        /// <summary>
        /// Removes the build file.
        /// </summary>
        public void RemoveBuildFile() {

            // Remove the selected build file
            if (this.SelectedBuildFile != null) {
                this.Project.BuildFiles.Remove(this.SelectedBuildFile);
            }
        }

        /// <summary>
        /// Edits the external build properties.
        /// </summary>
        public void EditExternalBuildProperties() {

            // Show external build properties editor
            ExternalBuildPropertiesView view = new ExternalBuildPropertiesView();

            if (this.View.SelectedBuildFile == null) {
                view.ViewType = ExternalBuildPropertiesEditListViewType.Solution;
                view.ExternalBuildProperties.AddRange(this.Project.ExternalBuildProperties);
            } else {
                view.ViewType = ExternalBuildPropertiesEditListViewType.BuildFile;
                view.ExternalBuildProperties.AddRange(this.SelectedBuildFile.ExternalBuildProperties);
            }

            view.Refresh();

            // Add external build properties to the project
            if (view.ShowDialog() == DialogResult.OK) {

                if (this.View.SelectedBuildFile == null) {
                    this.Project.ExternalBuildProperties.Clear();
                    this.Project.ExternalBuildProperties.AddRange(view.ExternalBuildProperties);

                } else {
                    this.SelectedBuildFile.ExternalBuildProperties.Clear();
                    this.SelectedBuildFile.ExternalBuildProperties.AddRange(view.ExternalBuildProperties);
                }
            }

            this.View.RefreshExternalBuildProperties();
        }

        /// <summary>
        /// Refreshes this instance.
        /// </summary>
        public override void Refresh() {
            this.View.State = TargetExecutionState.None;
            base.Refresh();
        }

        /// <summary>
        /// Views the refreshing.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ViewRefreshing(object sender, EventArgs e) {
            this.Refresh();
        }

        /// <summary>
        /// Views the edit external build properties.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ViewEditExternalBuildProperties(object sender, EventArgs e) {
            this.EditExternalBuildProperties();
        }

        /// <summary>
        /// Views the remove build file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ViewRemoveBuildFile(object sender, EventArgs e) {
            this.RemoveBuildFile();
        }

        /// <summary>
        /// Views the add build file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ViewAddBuildFile(object sender, EventArgs e) {
            this.AddBuildFile();
        }

        /// <summary>
        /// Views the execute build file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ViewExecuteBuildFile(object sender, EventArgs e) {
            this.ExecuteBuildFile();
        }

        /// <summary>
        /// Optionses the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OptionsChanged(object sender, EventArgs e) {
            this.View.RefreshProject();
            this.View.RefreshExternalBuildProperties();
        }

        /// <summary>
        /// Called when [selection changed].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnSelectionChanged(object sender, EventArgs e) {
            if (this.SelectionChanged != null) {
                this.SelectionChanged(sender, e);
            }
        }

        /// <summary>
        /// Called when [open file].
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="AntEater.Runtime.UI.BuildFileViewEventArgs"/> instance containing the event data.</param>
        private void OnOpenFile(object sender, BuildFileViewEventArgs e) {
            if (this.OpenFile != null) {
                this.OpenFile(sender, e);
            }
        }
    }
}
